package com.yuefresh.core;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.NonUniqueResultException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.yuefresh.Constants;

/**
 *
 * @author Junhao
 */
@Service
@SuppressWarnings("unchecked")
public class HibernateInvoker {
	@Autowired private SessionFactory sessionFactory;

	protected Session getSession() {
		return sessionFactory.getCurrentSession();
	}

	public <T> T get(Class<T> entityClass, Serializable id) {
		if (entityClass == null || id == null)
			return null;
		return (T) getSession().get(entityClass, id);
	}

	public void save(Object entity) {
		if (entity != null) {
			getSession().saveOrUpdate(entity);
			getSession().flush();
		}
	}

	public void delete(Object entity) {
		if (entity != null) {
			getSession().delete(entity);
			getSession().flush();
		}
	}
	public void delete(Collection<?> entities) {
		if (entities != null) {
			for (Object entity : entities) {
				if (entity != null)
					getSession().delete(entity);
			}
			getSession().flush();
		}
	}
	
	/**
	 * remove by hql
	 * @param values valiable parameter
	 */
	public void delete(String hql, Object... values) {
		Query query = getSession().createQuery(hql);
		for (int i = 0; i < values.length; i++) {
			query.setParameter(i, values[i]);
		}
		query.executeUpdate();
	}
	
	/**
	 * update by hql
	 * @param values valiable parameter
	 */
	public void update(String hql, Object... values) {
		Query query = getSession().createQuery(hql);
		for (int i = 0; i < values.length; i++) {
			query.setParameter(i, values[i]);
		}
		query.executeUpdate();
	}
	/*============Find object start*/
	public Object findUnique(String hql, Object... values) {
		return findUnique(false, hql, values);
	}

	public Object findUnique(boolean enableQueryCache, String hql,
			Object... values) {
		Query queryObject = createQuery(hql, enableQueryCache);
		if (values != null) {
			for (int i = 0; i < values.length; i++) {
				queryObject.setParameter(i, values[i]);
			}
		}
		try {
			return queryObject.uniqueResult();
		} catch (NonUniqueResultException e) {
			Log logger = LogFactory.getLog("CommonHibernateDao-findUnique");
			String error = "Not Unique:" + hql + "!";
			for (Object object : values) {
				error += object.toString() + " ";
			}
			logger.error(error);
			return queryObject.list().get(0);
		}
	}

	public <T> T findUnique(Class<T> entityClass, String hql, Object... values) {
		return findUnique(entityClass, false, hql, values);
	}

	public <T> T findUnique(Class<T> entityClass, boolean enableQueryCache,
			String hql, Object... values) {
		return (T) findUnique(enableQueryCache, hql, values);
	}

	public List<?> find(String hql, Object... values) {
		return find(false, hql, values);
	}

	public List<?> find(boolean enableQueryCache, String hql, Object... values) {
		if (hql == null)
			return new ArrayList<Object>();
		Query queryObject = createQuery(hql, enableQueryCache);
		queryObject.setMaxResults(Constants.MAX_QUERY_RESULTS);
		if (values != null) {
			for (int i = 0; i < values.length; i++) {
				queryObject.setParameter(i, values[i]);
			}
		}
		return queryObject.list();
	}

	public <T> List<T> find(Class<T> entityClass, String hql, Object... values) {
		return find(entityClass, false, hql, values);
	}

	public <T> List<T> find(Class<T> entityClass, boolean enableQueryCache,
			String hql, Object... values) {
		return (List<T>) find(enableQueryCache, hql, values);
	}
	
	protected Query createQuery(String hql, boolean enableQueryCache) {
		Query query = getSession().createQuery(hql);
		query.setTimeout(Constants.MAX_TIME_OUT);
		if (enableQueryCache) {
			query.setCacheable(true);
			query.setCacheRegion("QueryCache");
		}
		return query;
	}
	
	/**
	 * create Query object
	 * Example:
	 * 	caller.createQuery(hql)
	 * 	caller.createQuery(hql,arg0);
	 * 	caller.createQuery(hql,arg0,arg1);
	 * 	caller.createQuery(hql,new Model[arg0,arg1,arg2])
	 * @param values variable parameter
	 */
	public Query createQuery(String hql, Object... values) {
		Query query = getSession().createQuery(hql);
		query.setTimeout(Constants.MAX_TIME_OUT);
		for (int i = 0; i < values.length; i++) {
			query.setParameter(i, values[i]);
		}
		return query;
	}
	/*============Find object end*/
	
	/*==================page find start-------------*/
	/**
	 * Simple-----按过滤条件取头几笔数据.
	 */
	public <T> List<T> find(Class<T> entityClass, String hql, int limitCount, Object... values) {
		Query  query = this.createQuery(hql, values);
		query.setFirstResult(0);
		query.setMaxResults(limitCount);
		
		List<T> result = query.list();
		return result;
	}
	
	public Long count(String hql, Object... values) {
		if( hql.startsWith("select") ){
			hql = hql.substring(8);
		}
		Query countQuery = createQuery("select count(*) " + hql, values);
		Long totalCount = (Long)countQuery.uniqueResult();

		return totalCount;
	}
	
	/**
	 * 简单分页数据获取器.
	 */
	public <T> List<T> find(Class<T> entityClass, String hql, int pageNumber, int pageSize, Object... values) {
		Query  query = this.createQuery(hql, values);
		query.setFirstResult((pageNumber - 1) * pageSize);
		query.setMaxResults(pageSize);
		
		List<T> result = query.list();
		return result;
	}
	
	/**
	 * 按属性过滤条件列表分页查找对象.
	 */
	public <T> Page<T> find(Class<T> entityClass, final Page<T> page, String hql, Object... values) {
		Query countQuery = createQuery("select count(*) " + hql, values);
		if (page.isAutoCount()) {
			long totalCount = (Long)countQuery.uniqueResult();
			page.setTotalCount(totalCount);
		}
		
		if (page.isOrderBySetted()) {
			hql = hql + " order by " + page.getOrderBy();
		}
		Query query = this.createQuery(hql, values);
		query.setFirstResult(page.getFirst());
		query.setMaxResults(page.getPageSize());
		
		List<T> result = query.list();
		page.setResult(result);
		return page;
	}
	
	/**
	 * 按属性过滤条件列表分页查找对象.
	 */
	public <T> Page<T> find(Class<T> entityClass, final Page<T> page, String chql, String hql, Object... values) {
		Query countQuery = this.createQuery("select count(*) " + chql, values);
		if (page.isAutoCount()) {
			long totalCount = (Long)countQuery.uniqueResult();
			page.setTotalCount(totalCount);
		}
		
		if (page.isOrderBySetted()) {
			hql = hql + " order by " + page.getOrderBy();
		}
		Query query = this.createQuery(hql, values);
		query.setFirstResult(page.getFirst());
		query.setMaxResults(page.getPageSize());
		
		List<T> result = query.list();
		page.setResult(result);
		return page;
	}
	/*==================page find end-------------*/
}
